//! `std::hash` 模块的测试用例
//!
//! 本文件包含对 `std::hash` 模块中 `Hash` trait 和 `Hasher` 的测试。
//! 主要演示如何为自定义类型实现 `Hash`，以及如何使用 `DefaultHasher`。

#[cfg(test)]
mod tests {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::{Hash, Hasher};

    /// 一个自定义的结构体，我们将为它实现 `Hash`
    #[derive(Debug, PartialEq, Eq)]
    struct User {
        id: u32,
        username: String,
    }

    /// 为 `User` 结构体实现 `Hash` trait
    impl Hash for User {
        fn hash<H: Hasher>(&self, state: &mut H) {
            // 对每个字段调用 `hash` 方法
            // 字段的顺序很重要，不同的顺序会产生不同的哈希值
            self.id.hash(state);
            self.username.hash(state);
        }
    }

    /// 计算给定可哈希对象的哈希值
    fn calculate_hash<T: Hash>(t: &T) -> u64 {
        let mut hasher = DefaultHasher::new();
        t.hash(&mut hasher);
        hasher.finish()
    }

    /// 测试基本类型的哈希
    #[test]
    fn test_primitive_hash() {
        let hash1 = calculate_hash(&42);
        let hash2 = calculate_hash(&42);
        let hash3 = calculate_hash(&43);

        // 相同的值应该有相同的哈希值
        assert_eq!(hash1, hash2);
        // 不同的值通常有不同的哈希值
        assert_ne!(hash1, hash3);
    }

    /// 测试字符串的哈希
    #[test]
    fn test_string_hash() {
        let hash1 = calculate_hash(&"hello");
        let hash2 = calculate_hash(&"hello".to_string());
        let hash3 = calculate_hash(&"world");

        assert_eq!(hash1, hash2);
        assert_ne!(hash1, hash3);
    }

    /// 测试自定义结构体 `User` 的哈希
    #[test]
    fn test_custom_struct_hash() {
        let user1 = User {
            id: 1,
            username: "alice".to_string(),
        };
        let user2 = User {
            id: 1,
            username: "alice".to_string(),
        };
        let user3 = User {
            id: 2,
            username: "bob".to_string(),
        };

        let hash1 = calculate_hash(&user1);
        let hash2 = calculate_hash(&user2);
        let hash3 = calculate_hash(&user3);

        // 相同的实例应该有相同的哈希值
        assert_eq!(hash1, hash2);
        // 不同的实例通常有不同的哈希值
        assert_ne!(hash1, hash3);
    }

    /// 演示字段顺序对哈希值的影响
    #[test]
    fn test_field_order_matters() {
        struct Point {
            x: i32,
            y: i32,
        }

        impl Hash for Point {
            fn hash<H: Hasher>(&self, state: &mut H) {
                self.x.hash(state);
                self.y.hash(state);
            }
        }

        struct PointReversed {
            x: i32,
            y: i32,
        }

        impl Hash for PointReversed {
            fn hash<H: Hasher>(&self, state: &mut H) {
                // 哈希顺序与 Point 不同
                self.y.hash(state);
                self.x.hash(state);
            }
        }

        let p1 = Point { x: 1, y: 2 };
        let p2 = PointReversed { x: 1, y: 2 };

        // 即使字段值相同，但哈希顺序不同，哈希值也可能不同
        assert_ne!(calculate_hash(&p1), calculate_hash(&p2));
    }
}
